/*
 *	Copyright 2011 andro-inject developers 
 *	Licensed under the Apache License, Version 2.0 (the "License"); 
 *	you may not use this file except in compliance with the License. 
 *	You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 * 
 *	Unless required by applicable law or agreed to in writing, software 
 *	distributed under the License is distributed on an "AS IS" BASIS,
 *	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *	See the License for the specific language governing permissions and
 *	limitations under the License. 
 * 
*/

package com.androinject.core.factory.xml;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.androinject.core.definitions.ComponentDefinition;
import com.androinject.core.definitions.ComponentDefinitions;
import com.androinject.core.definitions.ComponentProperty;
import com.androinject.core.definitions.ManagedComponentDefinition;
import com.androinject.core.logging.Logger;
import com.androinject.core.logging.Logging;


public class SaxHandler extends DefaultHandler {
	
	private static Logger log = Logging.getLogger(SaxHandler.class);
	
	protected static final String TAG_COMPONENTS					= "components";
	protected static final String TAG_COMPONENT						= "component";
	protected static final String TAG_MANAGED_COMPONENT				= "managedComponent";
	protected static final String TAG_PROPERTY						= "property";
	
	protected static final String ATTRIBUTE_COMPONENTS_DEFAULT_INIT_METHOD	= "default-init-method";
	protected static final String ATTRIBUTE_COMPONENT_ID					= "id";
	protected static final String ATTRIBUTE_COMPONENT_CLASS					= "class";
	protected static final String ATTRIBUTE_COMPONENT_LAZY					= "lazy-init";
	protected static final String ATTRIBUTE_MANAGEDCOMPONENT_INIT_METHOD	= "init-method";
	protected static final String ATTRIBUTE_MANAGEDCOMPONENT_ID				= "id";
	protected static final String ATTRIBUTE_PROPERTY_NAME					= "name";
	protected static final String ATTRIBUTE_PROPERTY_REFERENCE				= "ref";
	
	
	protected ManagedComponentDefinition currentDefinition;
	protected ComponentDefinitions componentDefinitions;
	
	
	public SaxHandler() {
		this.componentDefinitions = new ComponentDefinitions();
	}
	
	
	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		super.startElement(uri, localName, qName, attributes);
		String tagName = qName;
		
		if (TAG_COMPONENTS.equals(tagName)) {
			this.handleComponentsStart(attributes);
			
		} else if (TAG_COMPONENT.equals(tagName)) {
			this.handleComponentStart(attributes);
			
		} else if (TAG_MANAGED_COMPONENT.equals(tagName)) {
			this.handleManagedComponentStart(attributes);
			
		} else if (TAG_PROPERTY.equals(tagName)) {
			this.handlePropertyStart(attributes);
		} 
	}
	
	
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		super.endElement(uri, localName, qName);
		
		String tagName = qName;
		if (TAG_COMPONENT.equals(tagName)) {
			this.handleComponentEnd();
			
		} else if (TAG_MANAGED_COMPONENT.equals(tagName)) {
			this.handleManagedComponentEnd();
		}
	}
	
	
	public ComponentDefinitions getComponentDefinitions() {
		return this.componentDefinitions;
	}
	
	
	protected void handleComponentStart(Attributes attributes) {
		ComponentDefinition definition = new ComponentDefinition();
		definition.setId(attributes.getValue(ATTRIBUTE_COMPONENT_ID));
		definition.setClassName(attributes.getValue(ATTRIBUTE_COMPONENT_CLASS));
		definition.setInitMethod(attributes.getValue(ATTRIBUTE_MANAGEDCOMPONENT_INIT_METHOD));
		definition.setLazyInitialization(Boolean.parseBoolean(attributes.getValue(ATTRIBUTE_COMPONENT_LAZY)));
		this.currentDefinition = definition;
	}
	
	
	protected void handleComponentEnd() {
		this.componentDefinitions.addComponentDefinition((ComponentDefinition)this.currentDefinition);
		log.trace("Adding component to componentDefinitions, id: " + this.currentDefinition.getId());
	}
	
	
	protected void handleManagedComponentStart(Attributes attributes) {
		ManagedComponentDefinition act = new ManagedComponentDefinition();
		act.setId(attributes.getValue(ATTRIBUTE_MANAGEDCOMPONENT_ID));
		act.setInitMethod(attributes.getValue(ATTRIBUTE_MANAGEDCOMPONENT_INIT_METHOD));
		this.currentDefinition = act;
	}
	
	
	protected void handleManagedComponentEnd() {
		this.componentDefinitions.addManagedComponentDefinition(this.currentDefinition);
		log.trace("Adding managed component to componentDefinitions, id: " + this.currentDefinition.getId());
	}
	
	
	protected void handlePropertyStart(Attributes attributes) {
		ComponentProperty property = new ComponentProperty();
		property.setName(attributes.getValue(ATTRIBUTE_PROPERTY_NAME));
		property.setReferencedComponentId(attributes.getValue(ATTRIBUTE_PROPERTY_REFERENCE));
		this.currentDefinition.getProperties().add(property);
	}

	
	protected void handleComponentsStart(Attributes attributes) {
		this.componentDefinitions.setDefaultInitMethodName(attributes.getValue(ATTRIBUTE_COMPONENTS_DEFAULT_INIT_METHOD));
	}
}
